package com.vrp3d.security.config;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.vrp3d.security.filter.CustomAuthenticationFilter;
import com.vrp3d.security.realm.CustomShiroRealm;
import com.vrp3d.security.realm.TokenValidateRealm;
import com.vrp3d.security.support.CustomModularRealmAuthenticator;
import com.vrp3d.security.support.CustomerHashedCredentialsMatcher;
import com.vrp3d.security.support.StatelessDefaultSubjectFactory;
import org.apache.shiro.authc.AbstractAuthenticator;
import org.apache.shiro.authc.credential.DefaultPasswordService;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.crypto.hash.DefaultHashService;
import org.apache.shiro.crypto.hash.format.Base64Format;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.Map;
import java.util.Set;

/**
 * shiro配置类
 *
 * @author vrp3d
 */
@Configuration
public class ShiroConfig {

    @Bean
    public AbstractAuthenticator customerAuthenticator() {
        // 自定义模块化认证器，用于解决多realm抛出异常问题
        ModularRealmAuthenticator authenticator = new CustomModularRealmAuthenticator();
        // 认证策略：AtLeastOneSuccessfulStrategy(默认)，AllSuccessfulStrategy，FirstSuccessfulStrategy
        authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        // 加入realms
        Set<Realm> realms = Sets.newHashSet();
        realms.add(customShiroRealm());
        realms.add(tokenValidateRealm());
        authenticator.setRealms(realms);
        return authenticator;
    }

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        Set<Realm> realms = Sets.newHashSet();
        realms.add(customShiroRealm());
        realms.add(tokenValidateRealm());
        securityManager.setRealms(realms);

        securityManager.setSessionManager(sessionManager());
        securityManager.setAuthenticator(customerAuthenticator());
        securityManager.setCacheManager(cacheManager());
        DefaultSubjectDAO subjectDAO = (DefaultSubjectDAO) securityManager.getSubjectDAO();
        DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator);
        securityManager.setSubjectFactory(subjectFactory());
        return securityManager;
    }

    /**
     * session 管理器 禁用session
     *
     * @return
     */
    @Bean
    public SessionManager sessionManager() {
        DefaultSessionManager sessionManager = new DefaultSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(false);
        return sessionManager;
    }

    /**
     * 用自己的factory替代,关闭session
     *
     * @return
     */
    @Bean
    public StatelessDefaultSubjectFactory subjectFactory() {
        return new StatelessDefaultSubjectFactory();
    }

    /**
     * shiro 生命周期管理器
     *
     * @return
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }

    @Bean
    public DefaultPasswordService defaultPasswordService() {
        DefaultPasswordService defaultPasswordService = new DefaultPasswordService();
        defaultPasswordService.setHashService(defaultHashService());
        defaultPasswordService.setHashFormat(defaultCryptFormat());
        return defaultPasswordService;
    }

    @Bean
    public DefaultHashService defaultHashService() {
        DefaultHashService defaultHashService = new DefaultHashService();
        defaultHashService.setHashIterations(2);
        defaultHashService.setHashAlgorithmName("md5");
        return defaultHashService;
    }

    @Bean
    public Base64Format defaultCryptFormat() {
        return new Base64Format();
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setLoginUrl("/login");
        factoryBean.setSecurityManager(securityManager());
        Map<String, Filter> filterMap = Maps.newLinkedHashMap();
        filterMap.put("jwt", customAuthenticationFilter());
        factoryBean.setFilters(filterMap);
        Map<String, String> filterChain = Maps.newLinkedHashMap();
        /*
         * 放开登录
         * 获取登录验证码
         * 验证码登录
         * 手机号/邮箱找回密码,发送验证码/邮件
         * 校验找回密码验证码
         * 找回密码,重置密码
         */
        filterChain.put("/login", "anon");
        filterChain.put("/getPhoneVerificationCodeWhenRegistering", "anon");
        filterChain.put("/registered", "anon");
        filterChain.put("/getRecoverPasswordVerificationCode", "anon");
        filterChain.put("/recoverPassword", "anon");

        // 放开swagger
//        filterChain.put("/swagger-ui.html", "anon");
        filterChain.put("/doc.html", "anon");
        filterChain.put("/webjars/**", "anon");
        filterChain.put("/swagger-resources/**", "anon");
        filterChain.put("/v2/**", "anon");

        filterChain.put("/showroom/getTypeList", "anon");
        filterChain.put("/showroom/getShowroomListFront", "anon");
        filterChain.put("/booth/selectShowroomAllBoothByShowroomId", "anon");
        filterChain.put("/booth/echoWhetherThereIsInformationOnTheBoothFront", "anon");
        filterChain.put("/booth/selectBoothByShowroomIdAndBoothOrderFront", "anon");


        // todo 测试阶段,全部放开
//        filterChain.put("/**", "anon");
        filterChain.put("/**", "jwt");
        factoryBean.setFilterChainDefinitionMap(filterChain);
        return factoryBean;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager());
        return advisor;
    }

    /**
     * 密码匹配规则配置
     *
     * @return
     */
    @Bean
    public CustomerHashedCredentialsMatcher credentialsMatcher() {
        CustomerHashedCredentialsMatcher matcher = new CustomerHashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");
        matcher.setHashIterations(2);
        matcher.setStoredCredentialsHexEncoded(false);
        return matcher;
    }

    @Bean
    public CustomShiroRealm customShiroRealm() {
        CustomShiroRealm shiroRealm = new CustomShiroRealm();
//        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return shiroRealm;
    }

    /**
     * 此处realm登录必须开启缓存，登录时会对这个参数进行判断，如果为false,则认证不通过
     *
     * @return
     */
    @Bean
    public TokenValidateRealm tokenValidateRealm() {
        TokenValidateRealm tokenValidateRealm = new TokenValidateRealm();
        tokenValidateRealm.setAuthenticationCachingEnabled(true);
//        tokenValidateRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return tokenValidateRealm;
    }

    /**
     * 开启shiro 注解支持
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 开启shiro授权注解，若上面Bean未生效则使用此Bean
     *
     * @return
     */
/*    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }*/
    @Bean
    public EhCacheManager cacheManager() {
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:ehcache/ehcache.xml");
        return cacheManager;
    }

    @Bean
    public CustomAuthenticationFilter customAuthenticationFilter() {
        return new CustomAuthenticationFilter();
    }

    @Bean
    public FilterRegistrationBean jwtFilterRegistration(CustomAuthenticationFilter filter) {
        FilterRegistrationBean registration = new FilterRegistrationBean(filter);
        registration.setEnabled(false);
        return registration;
    }
}